package com.onlyxiahui.common.dispatcher.impl;

import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSONObject;
import com.onlyxiahui.common.annotation.validate.Validate;
import com.onlyxiahui.common.annotation.validate.Validates;
import com.onlyxiahui.common.dispatcher.constant.ActionConstant;
import com.onlyxiahui.common.dispatcher.constant.DataConstant;
import com.onlyxiahui.common.dispatcher.constant.HeadCommonConstant;
import com.onlyxiahui.common.dispatcher.exception.MessageFormatException;
import com.onlyxiahui.common.dispatcher.exception.MessageValidException;
import com.onlyxiahui.common.dispatcher.util.DispatcherJsonUtil;
import com.onlyxiahui.common.message.base.ResultHead;
import com.onlyxiahui.common.message.util.HeadUtil;
import com.onlyxiahui.framework.action.dispatcher.ActionDispatcher;
import com.onlyxiahui.framework.action.dispatcher.common.ActionMethod;
import com.onlyxiahui.framework.action.dispatcher.common.ApplyInfo;
import com.onlyxiahui.framework.action.dispatcher.extend.ActionInterceptor;
import com.onlyxiahui.framework.action.dispatcher.extend.ActionRequest;
import com.onlyxiahui.framework.action.dispatcher.extend.ActionResponse;
import com.onlyxiahui.framework.action.dispatcher.extend.ArgumentBox;
import com.onlyxiahui.framework.json.validator.ValidatorResult;
import com.onlyxiahui.framework.json.validator.ValidatorService;
import com.onlyxiahui.framework.json.validator.error.ErrorInfoEnum;

/**
 * Date 2019-01-12 12:34:09<br>
 * Description
 * 
 * @author XiaHui<br>
 * @since 1.0.0
 */

public class ServiceActionInterceptor implements ActionInterceptor {

	private ValidatorService validatorService;
	private ActionDispatcher actionDispatcher;
	/**
	 * 需要校验的属性名
	 */
	private String validateProperty = "";

	public ServiceActionInterceptor(ActionDispatcher actionDispatcher) {
		super();
		this.actionDispatcher = actionDispatcher;
	}

	public ValidatorService getValidatorService() {
		return validatorService;
	}

	public void setValidatorService(ValidatorService validatorService) {
		this.validatorService = validatorService;
	}

	public String getValidateProperty() {
		return validateProperty;
	}

	public void setValidateProperty(String validateProperty) {
		this.validateProperty = validateProperty;
	}

	public boolean hasValidateProperty() {
		return null != this.validateProperty && !this.validateProperty.isEmpty();
	}

	@Override
	public ApplyInfo previous(ActionRequest request, ActionResponse response, ArgumentBox argumentBox) {
		boolean approve = true;
		Object value = null;
		JSONObject jsonObject = argumentBox.get(JSONObject.class);
		if (null == jsonObject) {
			Object requestData = request.getData();
			String message = (requestData instanceof String) ? requestData.toString() : "";
			if (DispatcherJsonUtil.maybeJson(message)) {
				jsonObject = JSONObject.parseObject(message);
				argumentBox.put(JSONObject.class, jsonObject);
			}
		}

		if (null != jsonObject) {

			String path = argumentBox.get(ActionConstant.REQUEST_PATH);

			boolean hasHead = jsonObject.containsKey(DataConstant.HEAD) && jsonObject.get(DataConstant.HEAD) instanceof JSONObject;

			if (hasHead) {
				JSONObject headJsonObject = jsonObject.getJSONObject(DataConstant.HEAD);
				ResultHead resultHead = argumentBox.get(ResultHead.class);
				if (null == resultHead) {
					resultHead = HeadUtil.toHead(headJsonObject);
					argumentBox.put(ResultHead.class, resultHead);
				}
				String action = headJsonObject.getString(HeadCommonConstant.ACTION);
				String method = headJsonObject.getString(HeadCommonConstant.METHOD);
				if (null == path) {
					String classCode = action == null ? "" : action;
					String methodCode = method;
					path = getPath(classCode, methodCode);
				}
			}

			JSONObject bodyJsonObject = null;
			if (hasValidateProperty()) {
				bodyJsonObject = (jsonObject.get(this.validateProperty) instanceof JSONObject) ? jsonObject.getJSONObject(this.validateProperty) : null;
			} else {
				bodyJsonObject = jsonObject;
			}

			if (null != bodyJsonObject) {

				if (null != validatorService) {
					List<ValidatorResult> list = new ArrayList<ValidatorResult>();
					ActionMethod method = request.getActionMethod();
					// actionDispatcher.getActionRegistry().getActionMethod(path);
					if (null != method) {
						Validates vs = method.getMethod().getAnnotation(Validates.class);
						if (null != vs) {
							validate(bodyJsonObject, vs, list);
						} else {
							Validate v = method.getMethod().getAnnotation(Validate.class);
							if (null != v) {
								validate(bodyJsonObject, v, list);
							} else {
								validate(bodyJsonObject, path, null, list);
							}
						}
					} else {
						validate(bodyJsonObject, path, null, list);
					}
					if (!list.isEmpty()) {
						approve = false;
						throw new MessageValidException(list);
					}
				}
			} else {
				String message = hasValidateProperty() ? "缺少：[" + this.validateProperty + "]" : "请求格式不正确!";
				approve = false;
				throw new MessageFormatException(message);
			}
		} else {
			throw new MessageFormatException("请求格式不正确！");
		}
		ApplyInfo applyInfo = new ApplyInfo();
		applyInfo.setApprove(approve);
		applyInfo.setValue(value);
		return applyInfo;
	}

	private void validate(JSONObject jsonObject, Validates vs, List<ValidatorResult> list) {
		if (null != vs) {
			Validate[] values = vs.value();
			if (null != values && values.length > 0) {
				for (Validate v : values) {
					validate(jsonObject, v, list);
				}
			}
		}
	}

	private void validate(JSONObject jsonObject, Validate v, List<ValidatorResult> list) {
		if (null != v && null != v.value() && !v.value().isEmpty()) {
			String name = v.value();
			String p = v.property();
			if (null != p && !p.isEmpty()) {
				Object jo = jsonObject.get(p);
				if (v.required() && null == jo) {
					list.add(new ValidatorResult(p, "不能为空！", ErrorInfoEnum.IS_NULL.code()));
				} else if (jo instanceof JSONObject) {
					validate((JSONObject) jo, name, p, list);
				}
			} else {
				validate(jsonObject, name, null, list);
			}
		}
	}

	private void validate(JSONObject jsonObject, String name, String property, List<ValidatorResult> list) {
		if (validatorService.hasValidate(name)) {
			List<ValidatorResult> vrs = validatorService.validate(jsonObject, name);
			if (!vrs.isEmpty()) {
				for (ValidatorResult vr : vrs) {
					StringBuilder sb = new StringBuilder();
					if (null != property && !property.isEmpty()) {
						sb.append(property);
						sb.append(".");
						sb.append(vr.getPropertyPath());
						vr.setPropertyPath(sb.toString());
					}
					list.add(vr);
				}
			}
		}
	}

	public String getPath(String classCode, String methodCode) {
		return actionDispatcher.getActionRegistry().getPath(classCode, methodCode);
	}
}
